﻿using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Transactions;
using T.ServiceComponent.I18N.SPI;
using T.FAS.Runtime.Base.Common;
using T.FAS.Runtime.Metadata.Entity;
using T.FAS.Runtime.Metadata.Client;
using T.FAS.Runtime.Term.Entity;
using T.ServiceComponent.Cache.Service;
using static T.FAS.Runtime.Metadata.Dao.RefSchemaService;

namespace T.FAS.Runtime.Term.Dao
{
    public class PageRefInstanceLogic
    {
        private static CacheService cacheService = CacheService.GetInstance("DefaultPool");
        readonly PageTermMappingDao termMappingDao = new PageTermMappingDao();
        readonly PageRefSchemaDao schemaDao = new PageRefSchemaDao();
        public PageRefInstanceLogic()
        {

        }
        /// <summary>
        /// 重新生成PageJS
        /// </summary>
        /// <returns></returns>
        public long GetPageVerMask(string pageMetaDataID, string pageMetaDataCode, string i18NID)
        {
            MetaDataClientService clientService = MetaDataClientService.GetInstance();
            List<MetaDataRefFlat> metaDataSchemas = new List<MetaDataRefFlat>();
            var translatedTerms = termMappingDao.GetTranslatedTerms(i18NID, pageMetaDataID);
            string fileName = FileTool.GetFileName($"Page{pageMetaDataCode}{i18NID}");
            var pageRefSchemas = schemaDao.GetPageRefSchemas(pageMetaDataID);
            foreach (var item in pageRefSchemas)
            {
                metaDataSchemas.Add(new MetaDataRefFlat { MetaDataID = item.MetaDataID, SchemaKey = item.SchemaKey, SchemaValue = item.MetaDataSchema });
            }
            string jsContent = clientService.RefSchemaServ.GenerateJSContent(translatedTerms, metaDataSchemas, pageMetaDataCode);
            string json = $"{{Name:\"{fileName}\",Extension:\"js\",PathId:\"141\",CustomFileName:\"{fileName}\"}}";
            FileTool.UploadFile(fileName, json, jsContent);
            return 100;
        }
        /// <summary>
        /// 重新生成公共JS
        /// </summary>
        /// <returns></returns>
        public void GetCommonVerMask(string i18NID)
        {
            MetaDataClientService clientService = MetaDataClientService.GetInstance();
            Dictionary<string, string> translatedTerms = termMappingDao.GetCommonTranslatedTerms(i18NID);
            string fileName = FileTool.GetFileName("fascommon" + i18NID);
            string jsContent = clientService.RefSchemaServ.GenerateJSContent(translatedTerms);
            string json = $"{{Name:\"{fileName}\",Extension:\"js\",PathId:\"141\",CustomFileName:\"{fileName}\"}}";
            FileTool.UploadFile(fileName, json, jsContent);
        }
        /// <summary>
        /// 运行时修改词条，重新生成PageJS 
        /// </summary>
        public void UpdateTermMappings(List<I18NPageTermMapping> i18NPageTerms)
        {
            if (i18NPageTerms == null)
                return;
            termMappingDao.UpdateTermMappings(i18NPageTerms);//更新词条信息
            RegenerationJSByTermMapping(i18NPageTerms);
        }
        /// <summary>
        /// 重新生成JS
        /// </summary>
        private void RegenerationJSByTermMapping(List<I18NPageTermMapping> i18NPageTerms)
        {
            List<string> languageIds = new List<string>();
            List<string> sourceIDs = new List<string>();
            List<string> termIDs = new List<string>();
            bool containsPublic = false;
            foreach (var map in i18NPageTerms)//获取影响元数据
            {
                if (map.TermUseType == 0)
                    containsPublic = true;
                if (!string.IsNullOrEmpty(map.CustomTermID) && !sourceIDs.Contains(map.SourceID))
                    sourceIDs.Add(map.SourceID);
                foreach (var item in map.TranslateItems)
                {
                    if (!string.IsNullOrEmpty(item.CustomText))
                    {
                        termIDs.Add(map.TermID);
                    }
                    if (!languageIds.Contains(item.Language))
                    {
                        languageIds.Add(item.Language);
                    }
                }
            }
            Task.Run(() =>
            {
                RegenerationJS(languageIds, sourceIDs, termIDs, containsPublic);
            });
        }
        /// <summary>
        /// 根据yTermMapping生成
        /// </summary>
        /// <param name="termMappingIDs"></param>
        public void RegenerationJSByTermMapping(List<string> termMappingIDs)
        {
            List<I18nLanguage> languages = new I18nLanguageDao().GetI18nLanguages();
            List<PageRefInstance> pageRefInstances = termMappingDao.GetPageRefInstancesByTermMapping(termMappingIDs);
            RegenerationJSByPageInfo(languages, pageRefInstances);
        }
        /// <summary>
        /// 根据翻译项重新生成JS
        /// </summary>
        /// <param name="i18NID"></param>
        public void RegenerationJS(List<string> termMappingIDs)
        {
            if (termMappingIDs.Count > 3000)
            {
                RegenerationAll();
            }
            else
            {
                RegenerationJSByTermMapping(termMappingIDs);
            }
        }
        /// <summary>
        /// 重新生成JS
        /// </summary>
        public void RegenerationJS(List<string> languageIds, List<string> sourceIDs, List<string> termIDs, bool containsPublic)
        {
            try
            {
                long varMask = (long)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds;
                if (sourceIDs.Count > 0)
                {
                    List<I18nLanguage> languages = new I18nLanguageDao().GetI18nLanguages();
                    List<PageRefInstance> pageRefInstances = termMappingDao.GetPageRefInstancesBySourceID(sourceIDs);
                    RegenerationJSByPageInfo(languages, pageRefInstances);
                }
                else if (termIDs.Count > 0)
                {
                    List<PageRefInstance> pageRefInstances = termMappingDao.GetPageRefInstancesByTermID(termIDs);
                    foreach (var language in languageIds)
                    {
                        if (containsPublic)
                            GetCommonVerMask(language);
                        foreach (var item in pageRefInstances)//重新生成JS
                        {
                            GetPageVerMask(item.PageMetaDataID, item.PageMetaDataCode, language);
                        }
                        UpdateRedis(pageRefInstances, new List<I18nLanguage> { new I18nLanguage { ID = language } }, varMask);
                    }
                }
            }
            catch (Exception e)
            {
                LogUtil.Log(e.ToString(), "Term");
            }
        }
        /// <summary>
        /// 根据来源ID生成JS
        /// </summary>
        /// <param name="i18NID"></param>
        public void RegenerationJSBySource(List<string> sourceIDs)
        {
            LogUtil.Log(JsonConvert.SerializeObject(sourceIDs), "Term");
            List<I18nLanguage> languages = new I18nLanguageDao().GetI18nLanguages();
            List<PageRefInstance> pageRefInstances = termMappingDao.GetPageRefInstancesBySourceID(sourceIDs);
            RegenerationJSByPageInfo(languages, pageRefInstances);
        }
        /// <summary>
        /// 根据语言与来源生成js
        /// </summary>
        /// <param name="languages"></param>
        /// <param name="pageRefInstances"></param>
        private void RegenerationJSByPageInfo(List<I18nLanguage> languages, List<PageRefInstance> pageRefInstances)
        {
            if (pageRefInstances.Count > 100)
            {
                Task.Run(() =>
                {
                    try
                    {
                        RegenerationJSByPage(languages, pageRefInstances);
                    }
                    catch(Exception e)
                    {
                        LogUtil.Log(e.ToString(), "Term");
                    }
                });
            }
            else
            {
                RegenerationJSByPage(languages, pageRefInstances);
            }
        }

        private void RegenerationJSByPage(List<I18nLanguage> languages, List<PageRefInstance> pageRefInstances)
        {
            long varMask = (long)(DateTime.Now - new DateTime(1970, 1, 1)).TotalSeconds;
            foreach (var language in languages)
            {
                GetCommonVerMask(language.ID);
                foreach (var item in pageRefInstances)//重新生成JS
                {
                    GetPageVerMask(item.PageMetaDataID, item.PageMetaDataCode, language.ID);
                }
            }
            UpdateRedis(pageRefInstances, languages, varMask);
        }

        /// <summary>
        /// 根据分支重新生成JS
        /// </summary>
        /// <param name="i18NID"></param>
        public void RegenerationJSByBranch(string branchID)
        {
            List<I18nLanguage> languages = new I18nLanguageDao().GetI18nLanguages();
            List<PageRefInstance> pageRefInstances = termMappingDao.GetPageRefInstancesByBranchID(branchID);
            RegenerationJSByPageInfo(languages, pageRefInstances);
        }
        /// <summary>
        /// 重新生成公共
        /// </summary>
        /// <param name="i18NID"></param>
        public void RegenerationCommon()
        {
            List<I18nLanguage> languages = new I18nLanguageDao().GetI18nLanguages();
            foreach (var language in languages)//所有语言
            {
                GetCommonVerMask(language.ID);
            }
        }
        /// <summary>
        /// 重新生成所有
        /// </summary>
        /// <param name="i18NID"></param>
        public void RegenerationAll()
        {
            List<I18nLanguage> languages = new I18nLanguageDao().GetI18nLanguages();
            List<PageRefInstance> pageRefInstances = termMappingDao.GetAllPageRefInstances();
            RegenerationJSByPageInfo(languages, pageRefInstances);
        }
        /// <summary>
        /// Page发布
        /// </summary>
        /// <param name="pageMetaDataID"></param>
        /// <param name="pageCode"></param>
        /// <param name="refInstances"></param>
        /// <param name="refSchemas"></param>
        public void Add(string pageMetaDataID, string pageCode, List<PageRefInstance> refInstances, List<PageRefSchema> refSchemas)
        {
            using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions() { IsolationLevel = IsolationLevel.ReadCommitted }))
            {
                schemaDao.Delete(new List<string> { pageMetaDataID });
                if (refSchemas != null && refSchemas.Count > 0)
                    schemaDao.Add(refSchemas);
                scope.Complete();
            }
            List<I18nLanguage> languages = new I18nLanguageDao().GetI18nLanguages();
            if (languages.Count > 0)
            {
                foreach (var language in languages)//所有语言
                {
                    GetPageVerMask(pageMetaDataID, pageCode, language.ID);
                }
            }
            else
            {
                GetPageVerMask(pageMetaDataID, pageCode, "zh-CN");
            }
        }
        /// <summary>
        /// 更新Redis时间戳
        /// </summary>
        /// <param name="pageRefInstances"></param>
        /// <param name="varMask"></param>
        public void UpdateRedis(List<PageRefInstance> pageRefInstances, List<I18nLanguage> languages, long varMask)
        {
            //语言包元数据更新时，更新redis中的版本号
            using (ICacheClient client = cacheService.GetClient())
            {
                using (ICachePipeline pipeline = client.CreatePipeline())
                {
                    foreach (I18nLanguage language in languages)
                    {
                        foreach (PageRefInstance item in pageRefInstances)
                        {
                            pipeline.QueueCommand((ICacheClient p) => p.Set($"LanguagePackageVarMask:{item.PageMetaDataID}:{language.ID}", varMask));
                        }
                    }
                    pipeline.Flush();
                }
            }
        }
    }
}

